package org.smile.beans.converter;

import java.lang.reflect.Array;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.smile.beans.BeanUtils;
import org.smile.exception.BeanException;
import org.smile.exception.ConvertException;
import org.smile.util.ClassTypeUtils;
import org.smile.util.ObjectLenUtils;
import org.smile.util.RegExp;

/**
 * 一个基本的转换器实现
 *   实现在基础数据 和date  list 几种类型的转换
 *   以及 list 的基础数据类型的泛型转换
 *   例如: bean 中是double类型  都会把map中的值向double转换 如不能解析则出异常
 *        bean 中是list 都会把map中的值转成list 如map 中是单个值就会把这个值加入到list中 
 *             如也是list直接转 ,是数据组则把数据转成list
 *        当bean中属性有泛型的时候，
 *        		当前只是实现了list的泛型 和 set 的泛型
 *                如map中是list 则会把map中的list的每一个object都向泛型类型转换
 *              并且只支持基础类型 日期 字符串 泛型                    
 * @author strive
 *
 */
public class BasicConverter implements Converter {
	
	protected static final Logger logger=Logger.getLogger(BasicConverter.class);
	/**
	 * 此工具适用的日期转换格式
	 */
	private static final DateFormat[] ACCEPT_DATE_FORMATS = {
			new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
			new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"),
			new SimpleDateFormat("yyyy-MM-dd"),
			new SimpleDateFormat("MM/dd/yyyy"), }; // 支持转换的日期格式
	
	private static final RegExp arraySplit=new RegExp("[,; ]+");
	/**
	 * 日期与字符串之间的转换方法 是字符串就转成日期 是日期就转成字符串
	 * 
	 * @param value
	 *            一个要转换的值 可以是日期格式的字符串 或 日期
	 * @return
	 * @throws Exception 
	 */
	@SuppressWarnings("unchecked")
	public Object convert(Class type,Class[] generic, Object value) throws ConvertException {
		if(type.getName().equals(value.getClass().getName())){
			return value;
		}
		//基础类型
		if(ClassTypeUtils.isBasicType(type)){
			return convertBasicType(type.getName(),value);
		}else{
			//为空
			if(value==null|type==value.getClass()){
				return value;
			}else if(Map.class.isAssignableFrom(type)){
				return covertToMap(generic,value);
			}else if(List.class.isAssignableFrom(type)){
				//转成List
				return converToList(generic,value);
			}else if(Set.class.isAssignableFrom(type)){
				//转换成set
				return converToSet(generic,value);
			}else{
				//转化目标类型是没有长度的类型 只取源对象的第一个
				if(ObjectLenUtils.hashLength(value)){
					value=ObjectLenUtils.get(value,0);
				}
				//转为整型
			    if(type==Integer.class){
					if(Integer.class.isInstance(value)){
						return value;
					}else{
						return Integer.parseInt(value+"");
					}
				}else if(type.equals(Long.class)){
					//长整型
					if(Long.class.isInstance(value)){
						return value;
					}else{
						return Long.parseLong(value+"");
					}
				}else if(type==Short.class){
					//短整型
					if(Short.class.isInstance(value)){
						return value;
					}else{
						return Short.parseShort(value+"");
					}
				}else if(type==String.class){
					if(value instanceof Object[]){
						return ""+((Object[])value)[0];
					}
					//字符串
					return value+"";
				}else if(type==Character.class){
					//字符
					return (Character)value;
				}else if(type==Double.class){
					//双精度
					if(Double.class.isInstance(value)){
						return value;
					}else{
						return Double.parseDouble(value+"");
					}
				}else if(type==Float.class){
					//单精度
					if(Float.class.isInstance(value)){
						return value;
					}else{
						return Float.parseFloat(value+"");
					}
				}else if(type==Boolean.class){
					return value;
				}else if(type==Date.class){
					//转成日期类型
					return convertToDate(value);
				}else if(value instanceof Map){
					try {
						return BeanUtils.newBean(type, (Map)value);
					} catch (BeanException e) {
						e.printStackTrace();
						throw new ConvertException("使用BaseConverter转换为bean类型出错"+type.getName(),e);
					}
				}else{
					throw new ConvertException("不支持的目标转换类型:"+type.getName()+"源类型"+value.getClass().getName());
				}
			}
		}
	}
	/**
	 * 转成map
	 * @param generic
	 * @param value
	 * @return
	 */
	private Object covertToMap(Class[] generic, Object value) throws ConvertException {
		if(generic==null&&value instanceof Map){
			return value;
		}else if(generic==null){
			try {
				return BeanUtils.mapFromBean(value);
			} catch (Exception e) {
				throw new ConvertException("从"+value.getClass().getName()+"转到map出错",e);
			}
		}else if(value instanceof Map){
			Map map=new HashMap();
			for(Map.Entry entry:(Set<Map.Entry>)((Map)value).entrySet()){
				Object key=this.convert(generic[0], null, entry.getKey());
				Object val=this.convert(generic[1], null, entry.getValue());
				map.put(key, val);
			}
			return map;
		}else{
			throw new ConvertException("不支持的转换从"+value.getClass().getName()+"转到map出错");
		}
	}
	/***
	 * 基础数据类型转换
	 * @param type
	 * @param value
	 * @return
	 * @throws ConvertException
	 */
	public Object convertBasicType(String type,Object value) throws ConvertException{
		
		if(type.startsWith("[")){
			if("[I".equals(type)){
				boolean hasLen=ObjectLenUtils.hashLength(value);
				if(hasLen){
					int len=ObjectLenUtils.len(value);
					int[] result=new int[len];
					for(int i=0;i<len;i++){
						result[i]=Integer.parseInt(convertBasicType("int",ObjectLenUtils.get(value, i)).toString());
					}
					return result;
				}else{
					if(value instanceof String){
						String[] ss=arraySplit.split(value.toString());
						int[] result=new int[ss.length];
						for(int i=0;i<ss.length;i++){
							result[i]=Integer.parseInt(ss[i]);
						}
						return result;
					}else{
						int[] result=new int[0];
						result[0]=Integer.parseInt(convertBasicType("int",value).toString());
						return result;
					}
				}
			}else if("[L".equals(type)){
				boolean hasLen=ObjectLenUtils.hashLength(value);
				if(hasLen){
					int len=ObjectLenUtils.len(value);
					long[] result=new long[len];
					for(int i=0;i<len;i++){
						result[i]=Integer.parseInt(convertBasicType("long",ObjectLenUtils.get(value, i)).toString());
					}
					return result;
				}else{
					if(value instanceof String){
						String[] ss=arraySplit.split(value.toString());
						long[] result=new long[ss.length];
						for(int i=0;i<ss.length;i++){
							result[i]=Long.parseLong(ss[i]);
						}
						return result;
					}else{
						long[] result=new long[0];
						result[0]=Long.parseLong(convertBasicType("long",value).toString());
						return result;
					}
				}
			}else if("[F".equals(type)){
				boolean hasLen=ObjectLenUtils.hashLength(value);
				if(hasLen){
					int len=ObjectLenUtils.len(value);
					float[] result=new float[len];
					for(int i=0;i<len;i++){
						result[i]=Float.parseFloat(convertBasicType("float",Array.get(value, i)).toString());
					}
					return result;
				}else{
					if(value instanceof String){
						String[] ss=arraySplit.split(value.toString());
						float[] result=new float[ss.length];
						for(int i=0;i<ss.length;i++){
							result[i]=Float.parseFloat(ss[i]);
						}
						return result;
					}else{
						float[] result=new float[0];
						result[0]=Float.parseFloat(convertBasicType("float",value).toString());
						return result;
					}
				}
			}else if("[S".equals(type)){
				boolean hasLen=ObjectLenUtils.hashLength(value);
				if(hasLen){
					int len=ObjectLenUtils.len(value);
					short[] result=new short[len];
					for(int i=0;i<len;i++){
						result[i]=Short.parseShort(convertBasicType("short",Array.get(value, i)).toString());
					}
					return result;
				}else{
					if(value instanceof String){
						String[] ss=arraySplit.split(value.toString());
						short[] result=new short[ss.length];
						for(int i=0;i<ss.length;i++){
							result[i]=Short.parseShort(ss[i]);
						}
						return result;
					}else{
						short[] result=new short[0];
						result[0]=Short.parseShort(convertBasicType("short",value).toString());
						return result;
					}
				}
			}else if("[D".equals(type)){
				boolean hasLen=ObjectLenUtils.hashLength(value);
				if(hasLen){
					int len=ObjectLenUtils.len(value);
					double[] result=new double[len];
					for(int i=0;i<len;i++){
						result[i]=Double.parseDouble(convertBasicType("double",Array.get(value, i)).toString());
					}
					return result;
				}else{
					if(value instanceof String){
						String[] ss=arraySplit.split(value.toString());
						double[] result=new double[ss.length];
						for(int i=0;i<ss.length;i++){
							result[i]=Double.parseDouble(ss[i]);
						}
						return result;
					}else{
						double[] result=new double[0];
						result[0]=Double.parseDouble(convertBasicType("double",value).toString());
						return result;
					}
				}
			}else if("[Z".equals(type)){
				boolean hasLen=ObjectLenUtils.hashLength(value);
				if(hasLen){
					int len=ObjectLenUtils.len(value);
					boolean[] result=new boolean[len];
					for(int i=0;i<len;i++){
						result[i]=Boolean.parseBoolean(convertBasicType("boolean",Array.get(value, i)).toString());
					}
					return result;
				}else{
					if(value instanceof String){
						String[] ss=arraySplit.split(value.toString());
						boolean[] result=new boolean[ss.length];
						for(int i=0;i<ss.length;i++){
							result[i]=Boolean.parseBoolean(ss[i]);
						}
						return result;
					}else{
						boolean[] result=new boolean[0];
						result[0]=Boolean.parseBoolean(convertBasicType("boolean",value).toString());
						return result;
					}
				}
			}
		}else{
			if(ObjectLenUtils.hashLength(value)){
				value=ObjectLenUtils.get(value,0);
			}
			if("double".equals(type.toString())){
				return value==null?0:Double.parseDouble(value.toString());
			}else if("int".equals(type.toString())){
				return value==null?0:Integer.parseInt(value.toString());
			}else if("float".equals(type.toString())){
				return value==null?(float)0:Float.parseFloat(value.toString());
			}else if("long".equals(type.toString())){
				return value==null?0:Long.parseLong(value.toString());
			}else if("short".equals(type.toString())){
				return value==null?0:Short.parseShort(value.toString());
			}else if("char".equals(type.toString())){
				return value==null?0:(value.toString()).charAt(0);
			}else if("byte".equals(type.toString())){
				return value==null?0:Byte.parseByte(value.toString());
			}else if("boolean".equals(type.toString())){
				return value==null?false:Boolean.parseBoolean(value.toString());
			}else{
				throw new ConvertException("不支持的目标转换类型:"+type);
			}
		}
		return null;
	}
	/**
	 * 把一个值转换成一个set集合
	 * 如果是数组就把数组每一个添加到set并进行泛型转换
	 * 如果 是没有长度的对象 ，则把这个对象添加到 set中 即最得到的set只有一个长度
	 * @param generic
	 * @param value
	 * @return
	 * @throws ConvertException
	 */
	public Set converToSet(Class[] generic, Object value) throws ConvertException {
		
		Set set=new HashSet();
		//为空时,不做转换
		if(value==null){
			return null;
		}else if(value instanceof Collection){
			Collection collection=(Collection)value;
			if(generic!=null){
				for(Iterator iter=collection.iterator();iter.hasNext();){
					set.add(this.convert(generic[0], null, iter.next()));
				}
				return set;
			}else {
				for(Iterator iter=collection.iterator();iter.hasNext();){
					set.add(iter.next());
				}
				return set;
			}
		}else if(value instanceof Object[]){
			Object[] objs=(Object[])value;
			for(Object o:objs){
				if(generic!=null){
					set.add(this.convert(generic[0], null, o));
				}else{
					set.add(o);
				}
			}
		}else if(ObjectLenUtils.hashLength(value)){
			int len=ObjectLenUtils.len(value);
			for(int i=0;i<len;i++){
				set.add(ObjectLenUtils.get(value, i));
			}
		}else{
			if(generic!=null){
				set.add(this.convert(generic[0], null, value));
			}else{
				set.add(value);
			}
		}
		return set;
	}
	/**
	 * @param value
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public List converToList(Class[] generic,Object value) throws ConvertException{
		List list=new ArrayList();
		//为空时,不做转换
		if(value==null){
			return null;
		}else if(value instanceof List){
			Collection collection=(Collection)value;
			if(generic!=null){
				for(Iterator iter=collection.iterator();iter.hasNext();){
					list.add(this.convert(generic[0], null, iter.next()));
				}
				return list;
			}else {
				for(Iterator iter=collection.iterator();iter.hasNext();){
					list.add(iter.next());
				}
				return list;
			}
		}else if(value instanceof Object[]){
			Object[] objs=(Object[])value;
			for(Object o:objs){
				if(generic!=null){
					list.add(this.convert(generic[0], null, o));
				}else{
					list.add(o);
				}
			}
		}else if(ObjectLenUtils.hashLength(value)){
			int len=ObjectLenUtils.len(value);
			for(int i=0;i<len;i++){
				list.add(ObjectLenUtils.get(value, i));
			}
		}else{
			if(generic!=null){
				list.add(this.convert(generic[0], null, value));
			}else{
				list.add(value);
			}
		}
		return list;
	}
	/**
	 * 转换成日期
	 * @param value
	 * @return
	 * @throws Exception 
	 */
	public Date convertToDate(Object value) throws ConvertException{
		if(value==null){
			return null;
		}
		//已经是日期 ，不用转换了
		if(value instanceof Date){
			return (Date)value;
		}else if(value instanceof String){
			//如果是字符串 进行String to Date的转换
			String dateString = (String) value;
			// 获取日期的字符串
			for (DateFormat format : ACCEPT_DATE_FORMATS) {
				try {
					return format.parse(dateString);
					// 遍历日期支持格式，进行转换
				} catch (Exception e) {
					continue;
				}
			}
		}else if(value instanceof String[]){
			//如果是字符串 进行String to Date的转换
			String dateString = ((String[])value)[0];
			// 获取日期的字符串
			for (DateFormat format : ACCEPT_DATE_FORMATS) {
				try {
					return format.parse(dateString);
					// 遍历日期支持格式，进行转换
				} catch (Exception e) {
					continue;
				}
			}
		}
		throw new ConvertException("不正确的数据类型格式转换["+value.getClass().getName()+":"+value+"] TO java.util.Date");
	}
}
